#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <stdbool.h>
#include <poll.h>
#include "Channel.h"
#include "EventLoop.h"

#define MAX 1024

struct PollData
{
    int32_t maxFd;
    struct pollfd *fds;
};

static void *pollInit();
static int32_t pollAdd(struct Channel *channel, struct EventLoop *evLoop);
static int32_t pollRemove(struct Channel *channel, struct EventLoop *evLoop);
static int32_t pollModify(struct Channel *channel, struct EventLoop *evLoop);
static int32_t pollDispatch(struct EventLoop *evLoop, int32_t timeout);
static int32_t pollClear(struct EventLoop *evLoop);

struct Dispatcher PollDispatcher =
    {
        pollInit,
        pollAdd,
        pollRemove,
        pollModify,
        pollDispatch,
        pollClear};

static void *pollInit()
{
    struct PollData *pollData = (struct PollData *)malloc(sizeof(struct PollData));
    if (pollData == NULL)
    {
        perror("malloc error");
        exit(0);
    }
    pollData->maxFd = 0;
    pollData->fds = (struct pollfd *)malloc(sizeof(struct pollfd) * MAX);
    for (int32_t i = 0; i < MAX; i++)
    {
        pollData->fds[i].fd = -1;
        pollData->fds[i].events = 0;
        pollData->fds[i].revents = 0;
    }

    return pollData;
}

static int32_t pollAdd(struct Channel *channel, struct EventLoop *evLoop)
{
    struct PollData *pollData = (struct PollData *)evLoop->dispatcherData;
    int32_t i = 0;
    for (; i < MAX; i++)
    {
        if (pollData->fds[i].fd == -1)
        {
            pollData->fds[i].fd = channel->fd;
            if (channel->events & ReadEvent)
            {
                pollData->fds[i].events = POLLIN;
            }
            if (channel->events & WriteEvent)
            {
                pollData->fds[i].events |= POLLOUT;
            }
            pollData->maxFd = (pollData->maxFd > channel->fd) ? pollData->maxFd : channel->fd;
            break;
        }
        if (i == MAX)
        {
            return -1;
        }
    }
    return 0;
}

static int32_t pollRemove(struct Channel *channel, struct EventLoop *evLoop)
{
    struct PollData *pollData = (struct PollData *)evLoop->dispatcherData;
    int32_t i = 0;
    for (; i < MAX; i++)
    {
        if (pollData->fds[i].fd == channel->fd)
        {
            pollData->fds[i].fd = -1;
            pollData->fds[i].events = 0;
            pollData->fds[i].revents = 0;
            break;
        }
    }
    //通过channel释放对于的tcpConnection资源
    channel->destroyCallback(channel->arg);
    if (i == MAX)
    {
        return -1;
    }
    return 0;
}

static int32_t pollModify(struct Channel *channel, struct EventLoop *evLoop)
{
    struct PollData *pollData = (struct PollData *)evLoop->dispatcherData;
    int32_t i = 0;
    for (; i < MAX; i++)
    {
        if (pollData->fds[i].fd == channel->fd)
        {
            if (channel->events & ReadEvent)
            {
                pollData->fds[i].events = POLLIN;
            }
            if (channel->events & WriteEvent)
            {
                pollData->fds[i].events |= POLLOUT;
            }
            break;
        }
        if (i == MAX)
        {
            return -1;
        }
    }
    return 0;;
}

static int32_t pollDispatch(struct EventLoop *evLoop, int32_t timeout)
{
    struct PollData *pollData = (struct PollData *)evLoop->dispatcherData;
    int32_t count = poll(pollData->fds, pollData->maxFd + 1, timeout * 1000);
    if (count < 0)
    {
        perror("poll error");
    }
    for (int32_t i = 0; i < pollData->maxFd; i++)
    {   
        if(pollData->fds[i].fd == -1)
        {
            continue;
        }
        int32_t events = pollData->fds->revents;
        if (events & (POLLERR | POLLHUP))
        {
            // 对方断开了连接，删除fd
            //  pollRemove(Channel,evLoop);
            continue;
        }
        if (events & POLLIN)
        {
            eventActivate(evLoop, pollData->fds->fd, ReadEvent);
        }
        if (events & POLLOUT)
        {
            eventActivate(evLoop, pollData->fds->fd, WriteEvent);
        }
    }
    
    return 0;
}

static int32_t pollClear(struct EventLoop *evLoop)
{
    struct PollData *pollData = (struct PollData *)evLoop->dispatcherData;
    free(pollData->fds);
    free(pollData);
}
